// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__9793C644_C91F_4BA6_A176_44537782901A__INCLUDED_)
#define AFX_STDAFX_H__9793C644_C91F_4BA6_A176_44537782901A__INCLUDED_

#include <CryModuleDefs.h>
#define eCryModule eCryM_SoundSystem
#define RWI_NAME_TAG "RayWorldIntersection(Sound)"
#define PWI_NAME_TAG "PrimitiveWorldIntersection(Sound)"

#define CRYSOUNDSYSTEM_EXPORTS

#ifndef _RELEASE
  #define INCLUDE_AUDIO_PRODUCTION_CODE
#endif // _RELEASE

#ifdef INCLUDE_AUDIO_PRODUCTION_CODE
#ifndef CAFE
  #define INCLUDE_FMOD_EVENTNET_SYSTEM
#endif
#endif // INCLUDE_AUDIO_PRODUCTION_CODE

#include "platform.h"

#include "../CryCommon/CryPool/PoolAlloc.h"
#include "../CryCommon/CryDLMalloc.h"
#include <CryMemoryManager.h>
#include "../CryCommon/BucketAllocator.h"
#include "../CryCommon/CryMemoryAllocator.h"

#include "StlUtils.h"

#include "ProjectDefines.h"
#include "../CryCommon/CryMemReplay.h"

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

extern CryCriticalSection m_CSDebug;
extern int unsigned g_nStreamingDebugCount;








class IGeneralMemoryHeap;

// wrapper class for all sound allocations
// small allocations are redicred to the global bucket allocator
// smaller ones are capped in the GeneralAllocator
class CSoundAllocator
{
	// all allocations below nMaxSmallSize go into the systemwide allocator(and thus the system wide small allocation allocator)
	enum { nMaxSmallSize = 512 }; 

public:
	CSoundAllocator();
	~CSoundAllocator();

	void* AllocateRaw(size_t nSize, size_t nAlign,const char *sUsage);

	template<typename T>
	T Allocate( size_t nSize, size_t nAlign,const char *sUsage )
	{
		return reinterpret_cast<T>(AllocateRaw(nSize, nAlign,sUsage));
	}

	bool Free( void *ptr );

	size_t Size( void *ptr );	

	ILINE uint8* Data() const { return reinterpret_cast<uint8*>(m_mspaceBase); }
	ILINE size_t MemSize() const { return m_mspaceSize; }
	ILINE size_t MemFree() const { return m_mspaceSize - static_cast<size_t>(m_mspaceUsed); }
	ILINE size_t const FragmentCount()				const { return static_cast<size_t>(nAllocations); }	
	ILINE size_t const GetSmallAllocsSize()		const { return static_cast<size_t>(nSmallAllocationsSize); }
	ILINE size_t const GetSmallAllocsCount()	const { return static_cast<size_t>(nSmallAllocations); }

	void InitMem( size_t nSize, void*ptr );
	void UnInitMem();

	void Cleanup();

private:
#ifdef USE_GLOBAL_BUCKET_ALLOCATOR
	typedef BucketAllocator<BucketAllocatorDetail::DefaultTraits<10 * 1024 * 1024, BucketAllocatorDetail::SyncPolicyLocked, false> > SoundBuckets;
#else
  typedef node_alloc<eCryDefaultMalloc, true, 512 * 1024> SoundBuckets;
#endif

private:
	CSoundAllocator(const CSoundAllocator&);
	CSoundAllocator& operator = (const CSoundAllocator&);

private:
	void TrackSmallAlloc( void *ptr, size_t nSize )
	{		
#ifdef INCLUDE_AUDIO_PRODUCTION_CODE
		if(ptr)
		{
			CryInterlockedIncrement(&nSmallAllocations);
			CryInterlockedAdd(&nSmallAllocationsSize, nSize);
		}
#endif // INCLUDE_AUDIO_PRODUCTION_CODE
	}

	void TrackGeneralAlloc( void *ptr, size_t nSize )
	{
#ifdef INCLUDE_AUDIO_PRODUCTION_CODE
		if(ptr)
		{
			CryInterlockedIncrement(&nAllocations);
			CryInterlockedAdd(&nAllocationsSize, nSize);
		}
#endif // INCLUDE_AUDIO_PRODUCTION_CODE
	}

	void TrackSmallDealloc( void *ptr )
	{
#ifdef INCLUDE_AUDIO_PRODUCTION_CODE
		CryInterlockedDecrement(&nSmallAllocations);
		CryInterlockedAdd(&nSmallAllocationsSize, -static_cast<int>(Size(ptr)));
#endif // INCLUDE_AUDIO_PRODUCTION_CODE
	}

	void TrackGeneralDealloc( size_t sz )
	{
#ifdef INCLUDE_AUDIO_PRODUCTION_CODE
		CryInterlockedDecrement(&nAllocations);
		CryInterlockedAdd(&nAllocationsSize, -static_cast<int>(sz));
#endif // INCLUDE_AUDIO_PRODUCTION_CODE
	}

	void* m_mspaceBase;
	size_t m_mspaceSize;
	IGeneralMemoryHeap* m_mspace;
	volatile int m_mspaceUsed;

	SoundBuckets m_smallAllocator;

	volatile int nSmallAllocations;
	volatile int nAllocations;
	
	volatile int nSmallAllocationsSize;
	volatile int nAllocationsSize;
};

#include "STLSoundAllocator.h"

typedef NCryPoolAlloc::CThreadSafe< NCryPoolAlloc::CBestFit< NCryPoolAlloc::CReferenced< NCryPoolAlloc::CMemoryDynamic, 4*1024, true >, NCryPoolAlloc::CListItemReference > > tMemoryPoolReferenced;

extern CSoundAllocator g_MemoryPoolPrimary;

#define CRYSOUNDMEMORY_ALLIGNMENT 16

// These to Macros can be used to allocated in the SystemMemoryPool. It creates a new instance of PTR or uses a precreated instance of PTR
// It will only execute the constructor if the allocation succeeded
#define POOL_NEW_CREATE(CLASS, PTR) CLASS* PTR = (CLASS*)g_MemoryPoolPrimary.Allocate<void*>(sizeof(CLASS), CRYSOUNDMEMORY_ALLIGNMENT,#CLASS); !PTR ? 0 : new(PTR) CLASS
#define POOL_NEW(CLASS, PTR) PTR = (CLASS*)g_MemoryPoolPrimary.Allocate<void*>(sizeof(CLASS), CRYSOUNDMEMORY_ALLIGNMENT,#CLASS); !PTR ? 0 : new(PTR) CLASS
#define POOL_FREE(PTR) { stl::destruct(PTR); bool const bFreed = g_MemoryPoolPrimary.Free(PTR); assert(bFreed); }

// Memory Allocation
#ifdef PROVIDE_SECONDARY_POOL
extern tMemoryPoolReferenced g_MemoryPoolSoundSecondary;

inline void* Secondary_Allocate(unsigned int nSize)
{
	// Secondary Memory is Referenced. To not loose the handle, more memory is allocated
	// and at the beginning the handle is saved. FMOD gets the adress after the handle

	/* Allocate in Referenced Secondary Pool */
	size_t pAllocHandle	=	g_MemoryPoolSoundSecondary.Allocate<uint32>(nSize, CRYSOUNDMEMORY_ALLIGNMENT);
	void* pAlloc = NULL;

	assert(pAllocHandle);
	if (pAllocHandle)
	{
		pAlloc	=	g_MemoryPoolSoundSecondary.Resolve<void*>(pAllocHandle);
	}

	return pAlloc;
}

inline bool Secondary_Free(void* pFree)
{
	// Secondary Memory is Referenced. To not loose the handle, more memory is allocated
	// and at the beginning the handle is saved. FMOD gets the adress after the handle

	// retrieve handle
	bool bFreed = (pFree == NULL);//true by default when passing NULL



	{
		size_t pAllocHandle = g_MemoryPoolSoundSecondary.AddressToHandle(pFree);
		if(pAllocHandle)
		{
			unsigned int nOldSize = g_MemoryPoolSoundSecondary.Size(pAllocHandle);
			bFreed = g_MemoryPoolSoundSecondary.Free(pAllocHandle);
		}
	}
	return bFreed;
}
#endif //PROVIDE_SECONDARY_POOL

// temporary memory leak detection
//////////////////////////////////////////////////////////////////////////
//#include "VisualLeakDetector/vld.h"
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Choose one of these SoundLibraries

// FMODEX 400 Win32/Xenon
//#define SOUNDSYSTEM_USE_FMODEX400
//#undef SOUNDSYSTEM_USE_FMODEX400
//
// XAudio Xenon only
//#define SOUNDSYSTEM_USE_XENON_XAUDIO
//#undef SOUNDSYSTEM_USE_XENON_XAUDIO

// Disable Prototype sound library choice

// Win32 or Win64
//////////////////////////////////////////////////////////////////////////
#if (defined(WIN32) || defined(WIN64) || defined(gringo)) && !defined(XENON) && !defined(PS3) && !defined(CAFE)
	#include <windows.h>

  // We decide between platform and configuration in the project settings
  // They're all named the same just the paths differ
  #		pragma message (">>> include lib: libogg_static.lib")
  #		pragma comment(lib,"libogg_static.lib")
  #		pragma message (">>> include lib: libvorbis_static.lib")
  #		pragma comment(lib,"libvorbis_static.lib")
  #		pragma message (">>> include lib: libvorbisfile_static.lib")
  #		pragma comment(lib,"libvorbisfile_static.lib")

#endif

// Win32
//////////////////////////////////////////////////////////////////////////
#if defined(WIN32) && !defined(WIN64) && !defined(XENON) && !defined(PS3) && !defined(gringo) && !defined(CAFE)
	
	#		pragma message (">>> Win32:")
	#define SOUNDSYSTEM_USE_FMODEX400
	#undef SOUNDSYSTEM_USE_XENON_XAUDIO

	#if defined(CRYSOUNDSYSTEM_FMOD_RELEASE)
	#		pragma message (">>> include lib: fmodex_vc.lib")
	#		pragma comment(lib,"fmodex_vc.lib")
	#		pragma message (">>> include lib: fmod_event.lib")
	#		pragma comment(lib,"fmod_event.lib")
	#		pragma message (">>> include lib: fmod_event_net.lib")
	#		pragma comment(lib,"fmod_event_net.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_RELEASE_WITH_LOGGING)
	#		pragma message (">>> include lib: fmodexL_vc.lib")
	#		pragma comment(lib,"fmodexL_vc.lib")
	#		pragma message (">>> include lib: fmod_eventL.lib")
	#		pragma comment(lib,"fmod_eventL.lib")
	#		pragma message (">>> include lib: fmod_event_netL.lib")
	#		pragma comment(lib,"fmod_event_netL.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_RELEASE_FOR_TESTING)
	#		pragma message (">>> include lib: fmodexT_vc.lib")
	#		pragma comment(lib,"fmodexT_vc.lib")
	#		pragma message (">>> include lib: fmod_eventT.lib")
	#		pragma comment(lib,"fmod_eventT.lib")
	#		pragma message (">>> include lib: fmod_event_netT.lib")
	#		pragma comment(lib,"fmod_event_netT.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_DEBUG)
	#		pragma message (">>> include lib: fmodexD_vc.lib")
	#		pragma comment(lib,"fmodex_vc.lib")
	#		pragma message (">>> include lib: fmod_eventD.lib")
	#		pragma comment(lib,"fmod_event.lib")
	#		pragma message (">>> include lib: fmod_event_netD.lib")
	#		pragma comment(lib,"fmod_event_net.lib")
	#endif

#endif // Win32

// Win64
//////////////////////////////////////////////////////////////////////////
#if (defined(WIN64) || defined(gringo)) && !defined(XENON) && !defined(PS3) && !defined(CAFE)

	#		pragma message (">>> Win64:")
	#define SOUNDSYSTEM_USE_FMODEX400
	#undef SOUNDSYSTEM_USE_XENON_XAUDIO

	#if defined(CRYSOUNDSYSTEM_FMOD_RELEASE)
	#		pragma message (">>> include lib: fmodex64_vc.lib")
	#		pragma comment(lib,"fmodex64_vc.lib")
	#		pragma message (">>> include lib: fmod_event64.lib")
	#		pragma comment(lib,"fmod_event64.lib")
	#		pragma message (">>> include lib: fmod_event_net64.lib")
	#		pragma comment(lib,"fmod_event_net64.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_RELEASE_WITH_LOGGING)
	#		pragma message (">>> include lib: fmodexL64_vc.lib")
	#		pragma comment(lib,"fmodexL64_vc.lib")
	#		pragma message (">>> include lib: fmod_eventL64.lib")
	#		pragma comment(lib,"fmod_eventL64.lib")
	#		pragma message (">>> include lib: fmod_event_netL64.lib")
	#		pragma comment(lib,"fmod_event_netL64.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_RELEASE_FOR_TESTING)
	#		pragma message (">>> include lib: fmodexT64_vc.lib")
	#		pragma comment(lib,"fmodexT64_vc.lib")
	#		pragma message (">>> include lib: fmod_eventT64.lib")
	#		pragma comment(lib,"fmod_eventT64.lib")
	#		pragma message (">>> include lib: fmod_event_netT64.lib")
	#		pragma comment(lib,"fmod_event_netT64.lib")
	#elif defined(CRYSOUNDSYSTEM_FMOD_DEBUG)
	#		pragma message (">>> include lib: fmodexD64_vc.lib")
	#		pragma comment(lib,"fmodexD64_vc.lib")
	#		pragma message (">>> include lib: fmod_eventD64.lib")
	#		pragma comment(lib,"fmod_eventD64.lib")
	#		pragma message (">>> include lib: fmod_event_netD64.lib")
	#		pragma comment(lib,"fmod_event_netD64.lib")
	#endif

#endif // Win64

// XENON
//////////////////////////////////////////////////////////////////////////












































































// PS3
//////////////////////////////////////////////////////////////////////////













	#define PS3_MEM_FLAG 0


// Cafe
//////////////////////////////////////////////////////////////////////////




// Linux
//////////////////////////////////////////////////////////////////////////
#if defined(LINUX)

#		pragma message (">>> Linux:")
//#define SOUNDSYSTEM_USE_FMODEX400
#undef SOUNDSYSTEM_USE_XENON_XAUDIO

#endif // LINUX

#include <memory>
#include <map>
#include <vector>
#include <set>
#include <algorithm>





#include <ILog.h>
#include <IConsole.h>
#include <ISound.h>
#include <ISystem.h>

#include <Cry_Math.h>
#include <ICryPak.h>
//#include <vector.h>


inline void __cdecl __CRYTEKDLL_TRACE(const char *sFormat, ... ) PRINTF_PARAMS(1, 2);
inline void __cdecl __CRYTEKDLL_TRACE(const char *sFormat, ... )
{
	va_list vl;
	char sTraceString[1024];
	
	va_start(vl, sFormat);
	vsprintf_s(sTraceString, sFormat, vl);
	va_end(vl);

	strcat(sTraceString, "\n");

	CryLog( "%s",sTraceString );
	//::OutputDebugString(sTraceString);	
}

#define TRACE __CRYTEKDLL_TRACE

#if /* defined(_DEBUG) && */ defined(WIN32)
//class CHeapGuardian
//{
//public: CHeapGuardian() {assert (_CrtCheckMemory());} ~CHeapGuardian() {assert (_CrtCheckMemory());}
//};


//#define GUARD_HEAP //CHeapGuardian __heap_guardian

//#pragma message (">>> 'Guard Heap enable")
#define GUARD_HEAP	//if (_HEAPOK != _heapchk()) __asm int 3

#else
//#pragma message (">>> 'Guard Heap disable")
#define GUARD_HEAP
#endif

//structure which updates update time
struct SUpdateTimer
{
#ifdef ENABLE_LW_PROFILERS
	ILINE SUpdateTimer(uint32& updateTimeDst) : rUpdateTime(updateTimeDst)
	{
		QueryPerformanceCounter(&startTicks);
	}
	ILINE ~SUpdateTimer()
	{
		LARGE_INTEGER endTicks;
		QueryPerformanceCounter(&endTicks);
		rUpdateTime += (uint32)(endTicks.QuadPart - startTicks.QuadPart);
	}
	LARGE_INTEGER startTicks;
	uint32 &rUpdateTime;
	static float ConvertToMS(uint32 ticks)
	{
		LARGE_INTEGER freq; 
		QueryPerformanceFrequency(&freq); 
		float frequency = 1.f/(float)freq.QuadPart;
		return (float)ticks * 1000.f * frequency;
	}
#else
	ILINE SUpdateTimer(uint32& updateTimeDst){}
	static float ConvertToMS(uint32 ticks){return 0.f;}
#endif
};
#define UPDATE_TIMER SUpdateTimer t(m_UpdateTicks);

// TODO: reference additional headers your program requires here

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__9793C644_C91F_4BA6_A176_44537782901A__INCLUDED_)
